#include "MusinkSubmitter/MusinkSubmitter.h"
#include "XMessageBox.h"
#include <time.h>
#include "ml.h"
#include "wa_dlg.h"

// --------- Prototypes and globals: generic plugin things ------------
int			init(void);
void		config(HWND parent);
void		quit(void);
int			PluginMessageProc(int message_type, int param1, int param2, int param3);

WNDPROC lpWndProcOld;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

winampMediaLibraryPlugin plugin =
{
	MLHDR_VER,
	"ml_ex v0.1",
	init,
	quit,
  PluginMessageProc,
};

// ------- Prototypes and globals: Musink-specific things --------------------

// possible answers to conflicts dialog
enum conf_ans {conf_winamp, conf_musink, conf_wa_all, conf_mu_all};

void merge_library();
conf_ans conf_dialog(MusinkSong &, MusinkSong &);
void get_lib_updates();
void increment_plays();
void send_new_rating(std::string, int);
BOOL am_i_new(std::string &);
std::vector<std::string> get_library_list();
void update_library_info(std::vector<MusinkSong> &);

MusinkSubmitter* sub;
FILE* fh = NULL; // file for debugging

// ------ All functions ----------------

int init() {
 	BOOL new_player;
	std::string ID;

	lpWndProcOld = (WNDPROC)SetWindowLong(plugin.hwndWinampParent,GWL_WNDPROC,(LONG)WndProc);

	MessageBox(plugin.hwndWinampParent,"player started up","",MB_OK);

	// determine whether this is a New Player
	new_player = am_i_new(ID);

	// act accordingly
	if (new_player) {
		sub = new MusinkSubmitter();
		FILE* fp = fopen("C:\\Program Files\\Winamp\\Plugins\\Musink_data.dat", "a");
		fprintf(fp, "%s\n", sub->getID());
		fclose(fp);

		merge_library();
	} else {
		sub = new MusinkSubmitter(ID);

		get_lib_updates();
	}

	// file for debugging
	fh = fopen("C:\\Documents and Settings\\moorej3\\Desktop\\test.txt", "w");
	if (!fh) {
		printf("smeg.\n");
		exit(0);
	}

  return 0;
}

void quit() 
{
	fclose(fh); // dbc
}

// returns true if this is a "new player" - determined by a file
BOOL am_i_new(std::string & ID) {
	FILE* fp = fopen("C:\\Program Files\\Winamp\\Plugins\\Musink_data.dat", "r");
	if (fp == NULL) { // file doesn't exist -> create it
		fp = fopen("C:\\Program Files\\Winamp\\Plugins\\Musink_data.dat", "w");
		fprintf(fp, "Musink data file.  Please do not delete.\n");
		fclose(fp);
		return TRUE;
	} else { // file exists already
		char buffer[60];
		fgets(buffer, 55, fp); // read line
		fscanf(fp, "%s", buffer); // get ID
		ID = buffer;
		fclose(fp);
		return FALSE;
	}
}

// gets user input on how to handle a ratings conflict
conf_ans conf_dialog(MusinkSong & lib_version, MusinkSong & musink_version) {
	char msg[500];
	sprintf(msg, "You have different ratings for %s by %s on %s.\n",
	        lib_version.title, lib_version.artist, lib_version.album);
	sprintf(msg, "%sCurrent Winamp rating: %d.\nCurrent Musink rating: %d.\n",
	        msg, lib_version.rating, musink_version.rating);
	sprintf(msg, "%sUpdate Musink's rating to match Winamp's? ", msg);
	sprintf(msg, "%s(If no, will update Winamp's rating to match Musink's.)", msg);
	int id=XMessageBox(plugin.hwndWinampParent, msg, "", MB_YESNO|MB_YESTOALL|MB_NOTOALL);

	switch (id) {
		case IDYES:
			return conf_winamp;
		case IDNO:
			return conf_musink;
		case IDYESTOALL:
			return conf_wa_all;
		case IDNOTOALL:
			return conf_mu_all;
	}
	return conf_musink; // default just in case
}

std::vector<std::string> get_library_list() {
	std::vector<std::string> file_list;

	// put stuff here

	return file_list;
}

void update_library_info(std::vector<MusinkSong> & library) {
	itemRecord record;
	for (std::vector<MusinkSong>::iterator lp = library.begin();
	     lp != library.end(); lp++) {

		// get basic info from winamp about this file
		record.filename = (char*)lp->filePath.c_str();
		SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&record,ML_IPC_GETFILEINFO);
		lp->artist = record.artist;
		lp->album = record.album;
		lp->title = record.title;
		lp->duration = record.length;

		// update special info
		lp->rating = atoi(getRecordExtendedItem(&record, "RATING"))*2;
		lp->playCount += atoi(getRecordExtendedItem(&record, "PLAYCOUNT"));
		lp->lastPlayed = max(getRecordExtendedItem(&record, "LASTPLAY"), lp->lastPlayed);
	}
}

// merge our library with the DBM's library
void merge_library() {
	// get library information from Musink for our files
	std::vector<std::string> file_list = get_library_list();
	std::vector<MusinkSong> library = sub->songCollection(file_list);

	// update Musink's information with our own
	update_library_info(library);

	// database tries to merge them
	std::vector<MusinkSong> conflicts;
	sub->syncDatabases(library, conflicts);

	// handle conflicts
	std::vector<MusinkSong> conflict_updates;
	int num_conflicts = conflicts.size();
	std::vector<MusinkSong>::iterator lp = library.begin();
	std::vector<MusinkSong>::iterator cp = conflicts.begin();
	while (num_conflicts > 0) {
		conf_ans answer = conf_dialog(*lp, *cp);
		switch (answer) {
			case conf_winamp:
				conflict_updates.push_back(*lp);
				num_conflicts--;
				break;
			case conf_musink:
				conflict_updates.push_back(*cp);
				num_conflicts--;
				break;
			case conf_wa_all:
				conflict_updates.insert(conflict_updates.end(), lp, library.end());
				num_conflicts = 0;
				break;
			case conf_mu_all:
				conflict_updates.insert(conflict_updates.end(), cp, conflicts.end());
				num_conflicts = 0;
				break;
		}
		lp++;
		cp++;
	}
	for (std::vector<MusinkSong>::iterator cp = conflict_updates.begin();
	     cp != conflict_updates.end(); cp++) {
		sub->updateSong(*cp);
	}
}

// get updates from the DBM
void get_lib_updates() {
	std::vector<MusinkSong> updates;
	sub->getChanges(updates);

	for (std::vector<MusinkSong>::iterator up = updates.begin();
	     up != updates.end(); up++) {
		// get winamp to give us the info for this file
		itemRecord record;
		record.filename = (char*)up->filePath.c_str();
		SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&record,ML_IPC_GETFILEINFO);

		// update our information accordingly
		char buffer[30];
		sprintf(buffer, "%d\0", (int)(up->rating/2));
		setRecordExtendedItem(&record, "RATING", buffer);
		sprintf(buffer, "%d\0", up->playCount);
		setRecordExtendedItem(&record, "PLAYCOUNT", buffer);
		sprintf(buffer, "%s\0", up->lastPlayed);
		setRecordExtendedItem(&record, "LASTPLAY", buffer);

		// write updated $record to the database (hopefully this works)
		SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&record,ML_IPC_DB_ADDORUPDATEITEM);

		// clean up after ourselves
		SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&record,ML_IPC_FREEFILEINFO);
	}
}

// having changed a rating, send it to the DBM
void send_new_rating(std::string song_file, int new_rating) {
	double scaled_rating = (new_rating/5.0)*10; // put it on a scale of 10
	MusinkSong s = sub->getSong(song_file);
	s.rating = scaled_rating;
	sub->updateSong(s);
}

// tell the DBM we played something
void increment_plays() {
	// get filename of current playing song - FIX THIS
	std::string song_file;
	song_file = (char*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 
	                   SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETLISTPOS),
	                   IPC_GETPLAYLISTFILE);
//	MessageBox(plugin.hwndWinampParent,song_file.c_str(),"",MB_OK);

	// create song object and increment its playcount
	MusinkSong s = sub->getSong(song_file);
	s.playCount++;

	// update last-played
	time_t raw_time;
	time(&raw_time);
	struct tm* time_info = localtime(&raw_time);
	char tdate[80];
	strftime(tdate,80,"%y%m%d %H:%M:%S",time_info);
	s.lastPlayed = tdate;

	// send it back
	sub->updateSong(s);
}

// calback function to catch ratings changes and playing of songs
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static std::string curr_song = "Foo - Bar.mp3"; // filename of song this message might be about
	int rating;
	char buf[20];

	switch (message) {
		case WM_WA_IPC: // 1024
			switch(lParam) {
				case IPC_PLAYING_FILE: // 3003
					MessageBox(plugin.hwndWinampParent,"started playing something","",MB_OK);
					increment_plays();
					break;
				case 65556: // right-clicked on a song
					mlAddTreeItemStruct this_song;
					// put stuff here: get the filename clicked on
					fprintf(fh, "msg %d wp %d lp %d %s\n", message, wParam, lParam, curr_song);
					break;
			}
			break;
		case 273: // rating changed
			rating = 40407-wParam;
			sprintf(buf, "new rating: %d\0", rating);
			send_new_rating(curr_song, rating);
			MessageBox(plugin.hwndWinampParent,buf,"",MB_OK);
			break;
	}
	return CallWindowProc(lpWndProcOld,hwnd,message,wParam,lParam);
}

int PluginMessageProc(int message_type, int param1, int param2, int param3)
{
  return 0;
}

extern "C" {

__declspec( dllexport ) winampMediaLibraryPlugin * winampGetMediaLibraryPlugin()
{
	return &plugin;
}

};
